为什么函数名称和变量名称不能在类中称为同一事物?

时间:2018-07-26 17:30:43

标签: python function

我的代码当前如下所示:

class Employee:

    def __init__(self, first, last):
        self.first = first
        self.last = last
        self.email = first + '.' + last + '@email.com'

    def email(self):
        return '{}.{}@email.com'.format(self.first, self.last)

    def fullname(self):
        return '{} {}'.format(self.first, self.last)

emp_1 = Employee('John', 'Smith')

emp_1.first = 'Jim'

print(emp_1.first)
print(emp_1.email())
print(emp_1.fullname())

我的输出给出:

Jim
Traceback (most recent call last):
  File "/home/djpoland/python-files/test.py", line 19, in <module>
    print(emp_1.email())
TypeError: 'str' object is not callable

我了解可以通过删除self.email或更改电子邮件功能的名称来解决此问题。但是,为什么变量名和函数不能具有相同的名称?这仅仅是Python标准约定还是此问题的内部原因?我尝试使用Google搜索来查找原因,但找不到任何信息。

5 个答案:

答案 0 :(得分:4)

因为在python中,类成员的内部表示形式是字典__dict__,它包含所有方法和实例变量的名称。而且由于字典中的键需要唯一,因此它们不能相同。本质上,方法和变量共享相同的名称空间(请参见下文)

确切地说,__dict__存储实例变量,只有在未找到给定键的情况下,它才会搜索方法也存储在名为__dict__的变量中的类变量。

因此,如果您这样做:

class Employee:

def __init__(self, first, last):
    self.first = first
    self.last = last

def email(self):
    return '{}.{}@email.com'.format(self.first, self.last)

def fullname(self):
    return '{} {}'.format(self.first, self.last)

emp1 = Employee("John","Doe")
print(emp1.__dict__)

您将获得{'first': 'John', 'last': 'Doe'}

因此,搜索将涉及类别变量:

 print(Employee.__dict__)

{'__module__': '__main__', '__init__': <function Employee.__init__ at 0x03933468>, 'email': <function Employee.email at 0x03933420>, 'fullname': <function Employee.fullname at 0x039333D8>, '__dict__': <attribute '__dict__' of 'Employee' objects>, '__weakref__': <attribute '__weakref__' of 'Employee' objects>, '__doc__': None}

在其中找到分配给功能的键email并调用它。

但是如果您的班级包含该字段:

班级雇员:

def __init__(self, first, last):
    self.first = first
    self.last = last
    self.email = "ple@ple.pl"

def email(self):
    return '{}.{}@email.com'.format(self.first, self.last)

def fullname(self):
    return '{} {}'.format(self.first, self.last)

print(emp1)
{'first': 'John', 'last': 'Doe', 'email': 'ple@ple.ple'}

搜索停止

正如@Max指出的,如果名称相同,则可以访问该方法。但是,应避免这种做法。我想不出这样的解决方案有效的例子。

答案 1 :(得分:2)

因为在Python中,方法只是一个“变量”(即实例变量,又称为属性),其值是一个函数。

答案 2 :(得分:1)

在python中,函数被视为对象。尽管这看起来很烦人,但实际上它非常有用,因为可以像其他任何对象一样传递函数。请考虑以下内容:

import java.io.*;

import org.apache.poi.hwpf.*;
import org.apache.poi.hwpf.usermodel.*;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;

import java.util.Map;
import java.util.HashMap;

public class WordReplaceTextInHWPFRuns {

 public static void main(String[] args) throws Exception {

  Map<String, String> items = new HashMap<>();
  items.put("toreplace1", "replacement1");
  items.put("toreplace2", "replacement2");

  boolean insideField = false;

  try (HWPFDocument doc = new HWPFDocument(new FileInputStream(new File("mydocument.doc")))) {

   Range range = doc.getRange();
   for (String k : items.keySet()) {
    String v = items.get(k);
    for (int r = 0; r < range.numCharacterRuns(); r++) {
     CharacterRun run = range.getCharacterRun(r);
     String text = run.text();

System.out.println(text);

     if (text.indexOf('\u0013') > -1) insideField = true;
     if (text.indexOf('\u0015') > -1) insideField = false;
     if (text.contains(k) && !insideField) {
      run.replaceText(k, v);

System.out.println("===========REPLACED=============");
System.out.println(run.text());

     }
    }
   }

   doc.write(new FileOutputStream(new File("mydocument_replaced.doc")));

  }
 }
}

输出:FileSystemWatcher watcher = new FileSystemWatcher() { Path = Google Drive path, NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName, Filter = "*.txt", EnableRaisingEvents = true }; watcher.Changed += new FileSystemEventHandler(ActionChecker.FileFound);

在此示例中,将def func(x): print 'Func executed' def run_func(f): f() run_func(func) 传递给函数Func executed时将其视为对象。请注意,func不会直接调用:即,该行是run_func而不是func

您可以想象,有很多非常有用的应用程序。

答案 3 :(得分:1)

这不是问题。根据该理论,一个对象不能有两个具有相似名称的成员。然后,当解释到Python时,在声明函数的那一行会给您一个错误。如果是C#或Java,编译时会给您一个错误。

因此它必须是一个概念主题。使用任何支持对象范例的语言,都会出现相同的错误。

答案 4 :(得分:1)

“基本上方法和变量共享相同的名称空间”,这并不是完全正确的。 事实是,即使您有一个名为email的实例变量,也可以访问email函数,怎么办? 使用emp_1.__class__.__dict__["email"](emp_1)

那到底发生了什么? 在python中,实例变量位于您指定的dict中,存储在类实例的变量__dict__中。 还有另一本词典,其中包含有关类实例 INCLUDING __dict__对象的更多信息。

当使用点运算符(.)访问类中的对象时,python首先搜索实例变量(__dict__对象),这说明了为什么尝试在函数中放置括号。 未能引发错误str object is not callable,因为您尝试调用以名称email找到的实例变量并对其进行了调用。

如果python没有找到与instance.__dict__中的点运算符名称相匹配的内容,它将开始在instance.__class__.__dict__中进行搜索,以尝试找到与该名称相匹配的方法。

另一个说明是,不可能使用两个具有相同名称的方法,因为如上所述,这些方法存储在instance.__class__.__dict__中的字典中,因此它们必须是唯一的。 如果您尝试这样做,它将仅覆盖其中之一,具体取决于顺序。

如果不清楚,请告诉我,我将举几个例子。