我的代码当前如下所示:
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搜索来查找原因,但找不到任何信息。
答案 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__
中的字典中,因此它们必须是唯一的。
如果您尝试这样做,它将仅覆盖其中之一,具体取决于顺序。
如果不清楚,请告诉我,我将举几个例子。