os.mkdir(MyClass()),TypeError:强制转换为Unicode,魔术方法

时间:2015-02-25 22:54:10

标签: python unicode magic-methods coercion

我想编写一个类,其实例应该可以用作os.mkdir()的参数。有没有一个神奇的方法,我可以添加到我的班级,以便这可以工作?使用__unicode __()的以下实现:

main.py:

import os

class MyClass(object):
    def __init__(self, string):
        self.__string = string
    def __unicode__(self):
        return unicode(self.__string)

obj = MyClass("/tmp/dir")
print unicode(obj)
os.mkdir(obj)

导致以下错误:

/tmp/dir
Traceback (most recent call last):
  File "main.py", line 11, in <module>
    os.mkdir(obj)
TypeError: coercing to Unicode: need string or buffer, MyClass found

我想在上下文中使用MyClass的实例,否则需要str或unicode。 E. g。为了制作&#34; abc&#34; + MyClass(&#34; def&#34;)工作,我可以在MyClass中实现__radd __()魔术方法。

编辑:解释我的意图的新代码示例(上面的MyClass对应于下面的StringRef):

import os

class StringRef(object):
    def __init__(self, string):
        self.__string = string
    def set_value(self, value):
        self.__string = value
    def __str__(self):
        return str(self.__string)
    def __repr__(self):
        return repr(self.__string)
    def __unicode__(self):
        return unicode(self.__string)
    def __add__(self, other):
        return self.__string + other
    def __radd__(self, other):
        return other + self.__string

class SomeClass(object):
    def __init__(self, directory):
        self.__directory = directory
    def use_dir1(self):
        print "directory: %s" % self.__directory
    def use_dir2(self):
        print "subdirectory:", self.__directory + "/subdir"
    def use_dir3(self):
        os.mkdir(self.__directory)
        os.rmdir(self.__directory)

print "* old *"
directory = "/tmp/dir1"
obj = SomeClass(directory)  # more objects can be created like this
obj.use_dir1()
directory = "/tmp/dir2"  # has no effect on the created objects
obj.use_dir1()

directory = "/tmp/dir1"
obj = SomeClass(directory)
obj.use_dir2()
directory = "/tmp/dir2"
obj.use_dir2()

directory = "/tmp/dir1"
obj = SomeClass(directory)
obj.use_dir3()
directory = "/tmp/dir2"
obj.use_dir3()


print "* new *"
directory = StringRef("/tmp/dir1")
obj = SomeClass(directory)  # more objects can be created like this
obj.use_dir1()
directory.set_value("/tmp/dir2")  # has effect on all created objects
obj.use_dir1()

directory = StringRef("/tmp/dir1")
obj = SomeClass(directory)
obj.use_dir2()
directory.set_value("/tmp/dir2")
obj.use_dir2()

directory = StringRef("/tmp/dir1")
obj = SomeClass(directory)
obj.use_dir3()
directory.set_value("/tmp/dir2")
obj.use_dir3()

输出:

* old *
directory: /tmp/dir1
directory: /tmp/dir1
subdirectory: /tmp/dir1/subdir
subdirectory: /tmp/dir1/subdir
* new *
directory: /tmp/dir1
directory: /tmp/dir2
subdirectory: /tmp/dir1/subdir
subdirectory: /tmp/dir2/subdir
Traceback (most recent call last):
  File "main.py", line 65, in <module>
    obj.use_dir3()
  File "main.py", line 27, in use_dir3
    os.mkdir(self.__directory)
TypeError: coercing to Unicode: need string or buffer, StringRef found

2nd Edit:StringRef(unicode)避免TypeError但不创建/ tmp / dir2:

import os

class StringRef(unicode):
    def __init__(self, string):
        self.__string = string
    def set_value(self, value):
        self.__string = value
    def __str__(self):
        return str(self.__string)
    def __repr__(self):
        return repr(self.__string)
    def __unicode__(self):
        return unicode(self.__string)
    def __add__(self, other):
        return self.__string + other
    def __radd__(self, other):
        return other + self.__string

class SomeClass(object):
    def __init__(self, directory):
        self.__directory = directory
    def use_directory(self):
        os.mkdir(self.__directory)

directory = StringRef("/tmp/dir1")
obj = SomeClass(directory)
obj.use_directory()
directory.set_value("/tmp/dir2")
obj.use_directory()

输出:

Traceback (most recent call last):
  File "main.py", line 29, in <module>
    obj.use_directory()
  File "main.py", line 23, in use_directory
    os.mkdir(self.__directory)
OSError: [Errno 17] File exists: '/tmp/dir1'

3 个答案:

答案 0 :(得分:1)

因为你希望这只小狗表现得像一个字符串,抱歉unicode,只是从unicode(内置的unicode类)而不是object中继承它。

#as per Padraic's remark that string <> unicode
#class MyClass(str):

class MyClass(unicode):
    pass


obj = MyClass("/tmp/dir")
print unicode(obj)
os.mkdir(obj)

#surprised that assigning a new attribute here works
#I woulda thought MyClass
#would be using __slots__.  oh well, better for you.
obj.foo = 1
print "obj.foo:%s" % (obj.foo)

答案 1 :(得分:0)

这是怎么回事?

(文件是testmkdir2.py)     import os

class MonkeyPatch(object):
    def __init__(self):
        self.func = os.mkdir

    def __call__(self, sortastring):
        if hasattr(sortastring,"value"):
            self.func(sortastring.value)
        else:
            self.func(sortastring)

mk = MonkeyPatch()

os.mkdir = mk

os.mkdir("/tmp/foo")

class Dummy(object):
    pass

sneakystring = Dummy()

sneakystring.value = "/tmp/foo2"

os.mkdir(sneakystring)

sneakystring.value = "/tmp/foo3"

os.mkdir(sneakystring)

$ ls -l / tmp / | grep foo $

$ python testmkdir2.py

$ ls / tmp / | grep foo

drwxr-xr-x 2 jluc wheel 68 26 Feb 20:19 foo

drwxr-xr-x 2 jluc wheel 68 26 Feb 20:19 foo2

drwxr-xr-x 2 jluc wheel 68 26 Feb 20:19 foo3

答案 2 :(得分:0)

我认为在传递给各种对象后,有一个字符串引用可以更改其值的最简洁方法是使用包含字符串值的对象并更改字符串引用的执行上下文与它的方式不同看起来如果使用字符串而不是字符串引用:新的执行上下文将是os.mkdir(s.value),&#34; string&#34; + s.value,s.value +&#34; string&#34;而不是os.mkdir(s),&#34; string&#34; + s,s +&#34; string&#34;):

class StringRef(object):
    def __init__(self, value):
        self.__value = value
    @property
    def value(self):
        return self.__value
    @value.setter
    def value(self, val):
        self.__value = val

class SomeClass(object):
    def __init__(self, s):
        self.__s = s
    def meth(self):
        print self.__s.value  # new execution context here

directory = StringRef("/tmp")
obj = SomeClass(directory)
obj.meth()
directory.value = "/var"
obj.meth()